<template>
  <div class="home-container">
    <SideMenu />
    <div class="main-content">
      <div class="content-layout">
        <!-- Left Column -->
        <div class="left-column">
          <!-- Assistant Info Section -->
          <div class="assistant-info-section">
            <el-form
              ref="formRef"
              :model="assistantForm"
              :rules="formRules"
              label-width="120px"
              class="config-form"
            >
              <el-form-item label="助手名称" prop="name" required>
                <el-input
                  v-model="assistantForm.name"
                  placeholder="请输入助手名称"
                />
              </el-form-item>

              <el-form-item label="描述信息" prop="description">
                <el-input
                  type="textarea"
                  v-model="assistantForm.description"
                  placeholder="请输入助手描述信息"
                  :rows="3"
                />
              </el-form-item>

              <el-form-item label="选择模型" prop="model" required>
                <el-select 
                  v-model="assistantForm.model" 
                  placeholder="请选择模型" 
                  class="model-select"
                >
                  <el-option
                    v-for="model in modelOptions"
                    :key="model.value"
                    :label="model.label"
                    :value="model.value"
                  />
                </el-select>
              </el-form-item>

              <el-form-item label="创建虚拟人">
                <el-switch
                  v-model="assistantForm.hasVirtualAssistant"
                  active-text="开启"
                  inactive-text="关闭"
                />
              </el-form-item>
            </el-form>
          </div>

          <!-- Prompt Input Section -->
          <div class="prompt-section">
            <div class="section-header">
              <span>提示词 {{ assistantForm.promptText.length }}</span>
              <el-button 
                type="primary" 
                size="small" 
                :loading="isGenerating"
                @click="handleGeneratePrompt"
              >生成</el-button>
            </div>
            <div class="prompt-input-wrapper">
              <el-input
                type="textarea"
                v-model="assistantForm.promptText"
                :placeholder="'在这里编写写你的提示词。也可以输入关键词，点击生成按钮生成提示词'"
                :rows="13"
                style="height: calc(100% - 40px);"
              />
            </div>
            <div class="prompt-footer">
              <el-button 
                type="primary" 
                :loading="isSaving"
                @click="handleSaveAssistant"
              >
                保存助手配置
              </el-button>
            </div>
          </div>
        </div>

        <!-- Right Column -->
        <div class="right-column">
          <div class="preview-section">
            <div class="preview-header">
              <span>调试与预览</span>
            </div>
            
            <div class="chat-container">
              <!-- 聊天消息区域 -->
              <div class="chat-messages">
                <template v-if="messages && messages.length">
                  <div v-for="(message, index) in messages" :key="index" class="message-wrapper">
                    <div class="message user" v-if="message.askRecord">
                      <div class="message-content">
                        <div class="text">{{ message.askRecord.content }}</div>
                      </div>
                    </div>
                    <div class="message system" v-if="message.answerRecord">
                      <div class="message-content">
                        <markdown-renderer v-if="message.answerRecord.content" :content="message.answerRecord.content" />
                      </div>
                    </div>
                  </div>
                </template>
                <template v-else>
                  <div class="no-messages">没有消息</div>
                </template>
              </div>
            </div>

            <!-- 底部输入区域 -->
            <div class="chat-input">
              <unified-input-bar
                :isBlocking="isBlocking"
                :isVoiceMode="false"
                :showRagMode="false"
                :artifacts="modelArtifacts"
                :selectedArtifact="selectedArtifact"
                @send="handleSend"
                @voice-result="handleVoiceResult"
                @toggle-mode="showVoiceInput = !showVoiceInput"
                @stop-all="handleStopAll"
                @select-artifact="handleSelectArtifact"
                @select-rag-mode="handleSelectRagMode"
              />
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted,computed,watch,nextTick,onUnmounted } from 'vue'
import { ElMessage } from 'element-plus'
import { useRouter,useRoute } from 'vue-router'
import { UpdateLLMAssistantRequest,CreateLLMAssistantRequest,GetLLMAssistantRequest, LLMAssistant, LLMModel, GeneratePromptRequest} from "@/types/proto/api/v1/llm_service";
import {GetAssistant, ListModels, GeneratePrompt,UpdateAssistant, CreateAssistant} from "@/api/llm"
import { useUserStore } from '@/store/user'
import SideMenu from '@/components/SideMenu.vue'
import UnifiedInputBar from '@/components/UnifiedInputBar.vue'
import { ExchangeReocrdUnit, RecordUnit } from '@/types/proto/api/v1/exchange_service'
import { WebSocketClient} from "@/utils/websocket";
import { InteractType, RagMode } from '@/types/proto/common/common';
import { AssistantTestRequest, AssistantTestResponse } from '@/types/proto/api/v1/llm_service';
import {AssistantTest} from "@/api/llm"
import { Exchange } from '@/types/proto/api/v1/exchange_service';
import { Phase } from '@/types/proto/api/v1/exchange_service';
import { getWssUrl } from '@/config';
import { DecodeExchange } from '@/api/knot';
import { ListLLMModelResponse } from '@/types/proto/api/v1/llm_service';
import MarkdownRenderer from '@/components/MarkdownRenderer.vue'

const isSaving = ref(false)
const assistant = ref<LLMAssistant | null>(null)
const llmModels = ref<LLMModel[]>([])
const userStore = useUserStore()
const router = useRouter()
const isGenerating = ref(false)
const models = ref<LLMModel[]>([])
const selectedArtifact =ref<string>('')
const currentArtifact = ref<string>('')
const messages = ref<ExchangeReocrdUnit[]|null>([]);
const wsSocket  = ref<WebSocketClient|null>(null);
const isPhaseEnd = ref(true)
const showVoiceInput = ref(true)

const modelArtifacts = computed(() => models.value.map(model => ({
    name: model.name || model.model,
    urn: model.urn
})))


const isBlocking = ref(false)
interface AssistantForm {
  name: string
  description: string
  promptText:string
  model: string
  modelName: string
  hasVirtualAssistant: boolean,
  currentAssistant: LLMAssistant|null,
}

const assistantForm = ref<AssistantForm>({
  name: '',
  description: '',
  model: '',
  promptText:'',
  modelName:'',
  hasVirtualAssistant: true,
  currentAssistant:null
})

const formRules = {
  name: [
    { required: true, message: '请输入助手名称', trigger: 'blur' },
    { min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
  ],
  modelType: [
    { required: true, message: '请选择模型', trigger: 'change' }
  ]
}

const formRef = ref()

const modelOptions = computed(() => llmModels.value.map(model => ({
                                        label: model.name,
                                        value: model.urn
                                    })))
const handleSelectArtifact = (urn: string) => {
  console.log('选择模型:', urn);
  selectedArtifact.value = urn
};

const handleSelectRagMode = (mode: string) => {
  
};

const handleVoiceResult = (ask: string) => {
  console.info('voice input:', ask);
}
const handleSaveAssistant = async () => {
  if (!formRef.value) return
  
  try {
    await formRef.value.validate()
    isSaving.value = true
    if (assistantForm.value.currentAssistant) {
        let a = {...assistantForm.value.currentAssistant}
        let updateMask = []
        if (a.name !== assistantForm.value.name) {
            a.name = assistantForm.value.name
            updateMask.push("name")
        }

        if (a.prompt !== assistantForm.value.promptText) {
            a.prompt = assistantForm.value.promptText
            updateMask.push("prompt")

        }

        if (a.model !== assistantForm.value.model) {
            a.model = assistantForm.value.model
            updateMask.push("model")
        }

        if (a.description !== assistantForm.value.description) {
            a.description = assistantForm.value.description
            updateMask.push("description")

        }

        if (a.virtUser !== assistantForm.value.hasVirtualAssistant) {
            a.virtUser = assistantForm.value.hasVirtualAssistant
            updateMask.push("virt_user")
        }


        let req = {assistant:a, updateMask:updateMask} as UpdateLLMAssistantRequest
        let res = await UpdateAssistant(req)
        console.log("update result:", res)
    } else {
        let req = {name: assistantForm.value.name,
            prompt:assistantForm.value.promptText,
            model:assistantForm.value.model,
            description:assistantForm.value.description,
            virtUser: assistantForm.value.hasVirtualAssistant,
        } as CreateLLMAssistantRequest
        let res = await CreateAssistant(req)
        console.log("create result:", res)
    }
    
    ElMessage.success('保存成功')
  } catch (error) {
    if (error instanceof Error) {
      console.error('保存失败:', error)
      ElMessage.error('保存失败，请重试')
    }
  } finally {
    isSaving.value = false
  }
}

const route = useRoute()
const parseParamFromRoute = async () => {
    try {
        console.log("parse param")
        const assistantUrn = route.query.assistant
        let reloadModel = true
        console.log("assistant urn:", assistantUrn)
        if (assistantUrn === null || assistantUrn === undefined) {
            assistantForm.value.currentAssistant = null
            reloadModel = false
        } else if (assistant.value != null) {
            if (assistant.value.urn === assistantUrn) {
                console.log("no need to reload")
                reloadModel = false
            }
        }

        const pageToken = { limit: 1000, offset: 0 }
        const filter = `model_type == 'chat'`
        let listRes = await ListModels({ pageSize: 1000, pageToken, filter: filter })
        llmModels.value = listRes.models

        if (reloadModel) {
            let req = {urn:assistantUrn} as GetLLMAssistantRequest
            let res = await GetAssistant(req)
            assistant.value = res
            
            
            console.log("assistant value:", assistant)
        } 

        if (assistant.value) {
            const currentModel = listRes.models.find(model => model.urn === assistant.value?.model)
            assistantForm.value = {
                name: assistant.value.name || '',
                description: assistant.value.description || '',
                model: assistant.value.model || '',
                hasVirtualAssistant: assistant.value.virtUser || false,
                promptText: assistant.value.prompt || '',
                modelName: currentModel?.name || '',
                currentAssistant:assistant.value
            }
            selectedArtifact.value = assistant.value.model
        }
    } catch (error) {
        console.error('Error parsing assistant from route:', error)
    }
}

const handleGeneratePrompt = async () => {
  try {
    isGenerating.value = true
    const currentPrompt = assistantForm.value.promptText
    let req = {instruction:currentPrompt, model:assistantForm.value.model} as GeneratePromptRequest
    const res = await GeneratePrompt(req)
    if (res && res.prompt) {
      assistantForm.value.promptText = res.prompt
      ElMessage.success('提示词生成成功')
    }
  } catch (error) {
    console.error('生成提示词失败:', error)
    ElMessage.error('生成提示词失败，请重试')
  } finally {
    isGenerating.value = false
  }
}

const handleSend  = async (message: string) => {
    console.log("send msg:", message)
    if (isBlocking.value) {
      console.error('isBlocking is true, return');
      return;
    }

    if (! messages.value) {
      messages.value = [];
    }

    let askunit = {
        content: message,
        createTime: new Date(),
    } as RecordUnit
    
    let exchange = {
        askRecord: askunit,
        answerRecord: {}
    } as ExchangeReocrdUnit;
    messages.value.push(exchange);
    
    // await nextTick();
    scrollToBottom();
    if (currentArtifact.value != selectedArtifact.value) {
      currentArtifact.value = selectedArtifact.value
      if (wsSocket.value && wsSocket.value.status() === WebSocket.OPEN) {
        wsSocket.value.close();
        wsSocket.value = null;
      }
    }
    
    isBlocking.value = true; 
    console.log('set isBlocking to true');
    if (wsSocket.value && wsSocket.value.status() === WebSocket.OPEN) {
      if (isPhaseEnd.value) {
        sendMessageViaWebSocket(message, Phase.HELLO);
      } else {
        sendMessageViaWebSocket(message);
      }
    } else {
      wsSocket.value = null;
      try {
        assistantTest(message);
      } catch (error) {
        console.error('Failed to test assistant:', error);
        updateLastMessage('抱歉，发生了一些错误。请稍后再试。');
      }
    }
};

const updateLastMessage = (content: string, isAppend: boolean = false, isCompleted: boolean = false) => {
    if (! messages.value) {
        return
    }

    if (messages.value.length === 0) return;

    let record = messages.value[messages.value.length - 1].answerRecord
    if (! record) {
        record = {} as RecordUnit
        messages.value[messages.value.length - 1].answerRecord = record
    }
    // 更新消息显示
    if (isAppend) {
       record.content += content;
    } else {
        record.content  = content;
    }

    messages.value[messages.value.length - 1].answerRecord  = record
    scrollToBottom();
};

const assistantTest = async (message: string) => {
    const request = {
      content: message,
      urn: assistant.value?.urn,
      interactType: InteractType.CHAT,
      ragMode: RagMode.RAG_MODE_UNSPECIFIED,
      llmModel: selectedArtifact.value,
    } as AssistantTestRequest;

    console.log('prepare to RagTest:');
    AssistantTest(request).then((res:AssistantTestResponse) => {
        createWebSocketConnection(res.tid);
    })
}

const createWebSocketConnection = (tid: string) => {
    let u = getWssUrl();
    const wsUrl = `${u}/${tid}`;
    wsSocket.value = new WebSocketClient(wsUrl, {onMessage:onSayMessage});
    wsSocket.value.connect(() => {
            console.log('Connection is ready!');
            sendMessageViaWebSocket("", Phase.HELLO, tid)
    });
};

const onSayMessage = (message: any) => {
    if (! messages.value) {
        return
    }
    if (messages.value.length === 0) return;
    console.log('onSayMessage:', message);
    try {
      const res = DecodeExchange(message);
      console.log('onSayMessage res:', res);
      let isAppend = true
      switch (res.phase) {
          case Phase.Close:
              isPhaseEnd.value = true
              console.log('WebSocket message received phase close');
              wsSocket.value?.close();
              wsSocket.value = null;
              break;
          case Phase.Begin:
              updateLastMessage(res.content, true, false);
              break
          case Phase.End:
              isPhaseEnd.value = true
              console.log('WebSocket message received phase end:',res);
              messages.value[messages.value.length - 1].answerId = res.answerId;
              updateLastMessage(res.content, true, true);
              isBlocking.value = false; 
              console.error('set isBlocking to false');
              break;
          case Phase.Continue:
              isPhaseEnd.value = false
              if (messages.value[messages.value.length - 1].phase === Phase.Begin) {
                isAppend = false
              }
              updateLastMessage(res.content, isAppend);
              break;
          default:
              let lastMessage = messages.value[messages.value.length - 1];
              lastMessage.askId = res.askId
              lastMessage.answerId = res.answerId
              isPhaseEnd.value = false
              console.log('WebSocket message received phase:', res.phase);
              updateLastMessage(res.content);
              break;
        }
        messages.value[messages.value.length - 1].phase = res.phase
    } catch(error) {
      console.error('on message failed:', error);
      return;
    }

    scrollToBottom(); 
    console.log('onSayMessage end');
}

const sendMessageViaWebSocket = (message: string, p: Phase = Phase.Continue, id: string = "") => {
    const chatMessage = Exchange.create({
      phase: p,
      content: message, 
      askId: id,
      mode: RagMode.RAG_MODE_UNSPECIFIED,
    });
    const encodedMessage = Exchange.encode(chatMessage).finish();
    if (wsSocket.value && wsSocket.value.status() === WebSocket.OPEN) {
        wsSocket.value.send(encodedMessage);
    }
};

const scrollToBottom = () => {
    nextTick(() => {
        const container = document.querySelector('.chat-messages');
        if (container) {
            container.scrollTop = container.scrollHeight;
        }
    });
};

const handleStopAll = () => {
  // 处理停止所有操作的逻辑
}

onMounted(() => {
  console.log("assistant config on mounted")
  if (!userStore.token) {
    ElMessage.warning('请先登录')
    router.push('/signin')
    return
  }

  if (userStore.assistant != null) {
    assistant.value = userStore.assistant
  }
  parseParamFromRoute()
})

onUnmounted(() => {
  console.log("assistant config onUnmounted")
  if (wsSocket.value) {
    console.log("assistant config onUnmounted close wsSocket")
    wsSocket.value.close()
    wsSocket.value = null
  }
  isBlocking.value = false
  isPhaseEnd.value = true
})

</script>

<style scoped lang="scss">
.home-container {
  display: flex;
  max-width: 1440px;
  margin: 0 auto;
  padding: 0;
}

.main-content {
  flex: 1;
  margin-left: 100px;
  padding: 20px 40px;
}

.content-layout {
  display: flex;
  gap: 24px;
  height: 100%;
}

.left-column {
  flex: 1;
  max-width: 600px;
}

.right-column {
  flex: 1;
  min-width: 400px;
}

.prompt-config {
  padding: 20px;
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}

.prompt-section, .variables-section, .context-section, .preview-section {
  margin-bottom: 20px;
  background: #fff;
  padding: 15px;
  border-radius: 8px;
}

.char-count {
  text-align: right;
  color: #999;
  font-size: 12px;
}

.variable-hint, .context-hint {
  color: #666;
  font-size: 14px;
  padding: 10px 0;
}

.preview-section {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 40px);
  background: #fff;
  border-radius: 8px;
}

.chat-container {
  flex: 1;
  overflow: hidden;
  position: relative;
}

.chat-messages {
  height: 100%;
  overflow-y: auto;
  padding: 20px;
  background-color: #f5f7fa;
}

.message {
  margin-bottom: 24px;

  &.system {
    display: flex;
    align-items: flex-start;
    
    .message-content {
      flex: 1;
      max-width: 600px;
      text-align: left;
      
      .text {
        background-color: #F7F7F8;
        border-radius: 12px;
        padding: 12px 16px;
        font-size: 14px;
        line-height: 1.6;
        color: #1C1C1E;
        // white-space: pre-wrap;
        // word-wrap: break-word;
      }
    }
  }

  &.user {
    display: flex;
    justify-content: flex-end;
    
    .message-content {
      max-width: 600px;
      
      .text {
        background-color: #4E89FD;
        color: #ffffff;
        border-radius: 12px;
        padding: 12px 16px;
        font-size: 14px;
        line-height: 1.6;
      }
    }
  }
}

.no-messages {
  text-align: center;
  color: #999;
  padding: 20px;
}

.chat-input {
  position: relative;
  padding: 20px;
  background-color: #fff;
  border-top: 1px solid #eee;
}

.assistant-info-section {
  background: #fff;
  padding: 24px;
  border-radius: 8px;
  margin-bottom: 20px;

  .config-form {
    max-width: 800px;

    :deep(.el-form-item) {
      margin-bottom: 24px;

      .el-form-item__label {
        font-weight: 500;
        color: #333;
        line-height: 32px;
      }

      .el-form-item__content {
        display: flex;
        align-items: center;
      }
    }

    .model-select {
      width: 100%;
    }

    .el-input, .el-select {
      max-width: 500px;
    }
  }

  .save-section {
    margin-top: 32px;
    border-top: 1px solid #eee;
    padding-top: 24px;
    display: flex;
    justify-content: flex-end;
  }
}

.prompt-section {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 500px);
  
  .prompt-input-wrapper {
    flex: 1;
    margin-bottom: 20px;
    min-height: 280px;

    :deep(.el-textarea) {
      height: 100%;
      
      .el-textarea__inner {
        height: 100% !important;
        resize: none;
      }
    }
  }

  .prompt-footer {
    margin-top: 0;
    padding: 8px 0;
  }
}

@media screen and (max-width: 1440px) {
  .home-container {
    max-width: 100%;
  }
  
  .main-content {
    margin-left: 220px;
  }
}

@media screen and (max-width: 1200px) {
  .main-content {
    margin-left: 200px;
  }
}
</style>
